#pragma once
#include <core/time/time.h>
#include <uam/ServerTimeMgr.h>
#include <mutex>
#include <vector>
#include <map>
#include "SSCFETSQuote.h"
#include "SSXCQuote.h"
#include "SSBankQuote.h"
#include "CompanyReport.h"
#include "BondContainer.h"
#include "bondlib.h"
// ***************************************************************
//  SSCompanyReportManager   version:  1.0    
//  -------------------------------------------------------------
//  author:	Tony.luo
//    date: 2016-08-23
//   brief: 公司报价 broker报价，后续调整只有报价才分配内存
//  -------------------------------------------------------------
//  Copyright (C) 2016 - Sumscope All Rights Reserved
// ***************************************************************
// 
// ***************************************************************


// #ifdef DEL(p)
// 	#undef DEL(p)
// #endif

#define  DEL(p) if(p!=NULL){delete p; p=NULL;}

#if defined(WIN32) || defined(_WINDOWS)
#include <windows.h>

#define localtime_r(ti , tm) localtime_s(tm , ti)
#define gmtime_r(ti , tm) gmtime_s(tm , ti)

#else
#include <sys/time.h>
#endif


class StatDumper;
class S_BONDLIB_EXPORT CReportManagerBase{
public:
	typedef qb::base::HighResTime HighResTime;
	enum kActionType{
		kActionTypeAdd,
		kActionTypeClear,
		kActionTypeClearReport,
		kActionTypeReserve,
		kActionTypeGetReport,
		kActionTypeGetReportOrAdd,
		kActionTypeSetReport,
		kActionTypeCount
	};
	class ScopedDumper{
		StatDumper*	m_dumper;
		HighResTime m_timer;
		int			m_length;
		kActionType	m_type;
	public:
		ScopedDumper(StatDumper* dumper, kActionType type, int length);
		~ScopedDumper();
	};
protected:
	//typedef qboost::Spinlock LockType;
	//typedef qboost::ScopedSpinLock ScopedLockType;
	typedef std::recursive_mutex LockType;
	typedef std::lock_guard<std::recursive_mutex> ScopedLockType;

	StatDumper*		m_dumper;
	LockType		m_mutex;	//互斥信号
public:
	// 之所以将之前的CSPMutex在这里替换,是考虑性能
	using Scoped = ScopedLockType;
	CReportManagerBase();
	~CReportManagerBase();
	virtual int GetSize() const;
	virtual int GetMemory(int mode);

	/*
	by scofined.qi
	此宏是统计CSSReportManager对象的各个接口使用情况以及内存情况,注释和开启后均不影响代码执行,默认关闭
	对象在宏开启后,每间隔m_log_gap毫秒后输出一次日志,默认是4000ms
	部分接口已经加锁增加了安全性
	*/
#define SCOPED_REPORT_DUMPER(TYPE) //ScopedDumper _scoped(m_dumper, TYPE, m_vctRep.size());
public://调试用
	void SetName(const char* name);
	void SetItemSize(int itemSize);
	void DumpStatus(int mode = 0)const;
};
template<class T>
class S_BONDLIB_EXPORT CSSReportManager : public CReportManagerBase
{
public:
	CSSReportManager() :CReportManagerBase(){
		T t;
		SetName(t.GetName());
		SetItemSize(t.GetItemSize());
	}
	~CSSReportManager(){Clear();}

public:
	 bool Add(T* pReport)
	 {
		 ScopedLockType lock(m_mutex);
		 SCOPED_REPORT_DUMPER(kActionTypeAdd);
		 m_vctRep.push_back(pReport);
		 return true;
	 }

	 void Clear()
	 {
		 ScopedLockType lock(m_mutex);
		 SCOPED_REPORT_DUMPER(kActionTypeClear);
		 for ( size_t i=0; i<m_vctRep.size(); ++i )
		 {
			 DEL(m_vctRep[i]);
		 }
		 m_vctRep.clear();
	 }

	 void ClearReport()
	 {
		 ScopedLockType lock(m_mutex);
		 SCOPED_REPORT_DUMPER(kActionTypeClearReport);
		 for ( size_t i=0; i<m_vctRep.size(); ++i )
		 {
			 if ( m_vctRep[i] != NULL )
			 {
				 m_vctRep[i]->Clear();
			 }
		 }
	 }


	 void Reserve(int nCapacity)
	 {
		 ScopedLockType lock(m_mutex);
		 SCOPED_REPORT_DUMPER(kActionTypeReserve);
		 m_vctRep.reserve(nCapacity);
	 }

	 virtual int GetSize() const override{ 
		 int size = 0;
		 ScopedLockType lock(const_cast<LockType&>(m_mutex));
		 for (size_t i = 0; i < m_vctRep.size(); ++i)
		 {
			 if (m_vctRep[i])
				 size++;
		 }
		 return size;
	 }
	virtual int GetMemory(int mode)override 
	 {
		 int mem = 0;
		 ScopedLockType lock(m_mutex);
		 for (size_t i = 0; i < m_vctRep.size(); ++i)
		 {
			 if (m_vctRep[i])
				 mem += m_vctRep[i]->GetBytes(mode);
		 }
		 mem += m_vctRep.capacity()*sizeof(T*);
		 return mem;
	 }

	 T* GetReport(int nIndex)
	 {
		 //if (AfxGetUserAccountManager().IsBrokerMobileOnline())return NULL;
		 ScopedLockType lock(m_mutex);
		 SCOPED_REPORT_DUMPER(kActionTypeGetReport);
		 if (nIndex<0 || nIndex>=(int)m_vctRep.size())return nullptr;
		 return m_vctRep[nIndex];
	 }


	 //-------------------------------------------------------------------------
	 // Summary:
	 // 		得到报价对象，若不存在，则会自动创建出来.更新报价数据时使用
	 // Parameters:
	 // 		nIndex -  下标
	 // Returns:
	 // 		报价对象
	 //-------------------------------------------------------------------------
	 T* GetReportOrAdd(int nIndex)
	 {
		 if (nIndex < 0)
		 {
			 return NULL;
		 }
         int nBondSize = CBondContainer::instance().GetSize();
		 if (nIndex >= nBondSize)
		 {
			 return NULL;
		 }

		 ScopedLockType lock(m_mutex);
		 SCOPED_REPORT_DUMPER(kActionTypeGetReportOrAdd);
		 //债券容器增加数据时，需要扩展数据
		 if ( nIndex>=(int)m_vctRep.size())
		 {
			 m_vctRep.resize(nBondSize);
		 }

		 if ( m_vctRep[nIndex] == NULL)
		 {
			 m_vctRep[nIndex] = new T();
		 }
		 return m_vctRep[nIndex];
	 }


	 //-------------------------------------------------------------------------
	 // Summary:
	 // 		设置报价对象，
	 // Parameters:
	 // 		nIndex -  下标
	 // 		T* - 报价对象 必须是new的对象，clear会释放内存
	 // Returns:
	 // 		设置成功返回true
	 //-------------------------------------------------------------------------
	 bool SetReport(int nIndex,T* pObj)
	 {
		 ScopedLockType lock(m_mutex);
		 SCOPED_REPORT_DUMPER(kActionTypeSetReport);
		 if ( nIndex<0 || nIndex>=(int)m_vctRep.size() )
		 {
			 return false;
		 }

		 DEL(m_vctRep[nIndex]);
		 m_vctRep[nIndex] = pObj;
	 }

	 LockType& GetMutex(){ return m_mutex; }
private:
	std::vector<T*>	m_vctRep;		//报价
};

template<class T>
class S_BONDLIB_EXPORT CSSCFETSReportManager : public CSSReportManager<T>
{
public:
    CSSCFETSReportManager() : CSSReportManager<T>()
	{ 
		m_mapver[0] = 0; m_mapver[1] = 0; m_mapver[2] = 0;
		m_lastupdate = 0;
	}
	~CSSCFETSReportManager(){};

	void	ClearVersion()
	{
		for (std::map<int, int>::iterator it = m_mapver.begin(); it != m_mapver.end(); it++)
		{
			it->second = 0;
		}
		m_lastupdate = 0;
	}

	void	UpdateVersion(int type, int ver, time_t updatetime)
	{
		auto it = m_mapver.find(type);
		if (it == m_mapver.end())m_mapver.insert(make_pair(type, ver));
		else it->second = max(it->second, ver);
		m_lastupdate = max(m_lastupdate, updatetime);
	}

	int		GetVersion(int type){ return m_mapver[type]; }

	bool	isDayChanged()
	{
		struct tm tmLast = { 0 };
		struct tm tmNow = { 0 };
		time_t t = ServerTimeMgr::instance().serverTime();
        localtime_r(&m_lastupdate, &tmLast);
        localtime_r(&t, &tmNow);
		if (tmLast.tm_mday != tmNow.tm_mday || tmLast.tm_mon != tmNow.tm_mon || tmLast.tm_year != tmNow.tm_year)return true;
		return false;
	}

private:
	std::map<int, int>	m_mapver;
	time_t				m_lastupdate;	//最后更新时间
};


template<class T>
class S_BONDLIB_EXPORT CSSCFETSDealQuoteManager : public CSSReportManager<T>
{
public:
    CSSCFETSDealQuoteManager() : CSSReportManager<T>()
	{
		m_ver = 0;
		m_lastupdate = 0;
	}
	~CSSCFETSDealQuoteManager(){};

	void	ClearVersion(){ m_ver = 0; m_lastupdate = 0; }
	void	UpdateVersion(int ver, time_t updatetime)
	{
		m_ver = max(m_ver, ver);
		m_lastupdate = max(m_lastupdate, updatetime);
	}

	int		GetVersion(){ return m_ver; }

	bool	isDayChanged()
	{
		struct tm tmLast = { 0 };
		struct tm tmNow = { 0 };
		time_t t = ServerTimeMgr::instance().serverTime();
        localtime_r(&m_lastupdate, &tmLast);
        localtime_r(&t, &tmNow);
		if (tmLast.tm_mday != tmNow.tm_mday || tmLast.tm_mon != tmNow.tm_mon || tmLast.tm_year != tmNow.tm_year)return true;
		return false;
	}

private:
	int				m_ver;
	time_t			m_lastupdate;	//最后更新时间
};

class CBondCompanyRep;
class CBondBankRep;
class CXCQuoteRep;
class CCFETSQuoteRep;
class CCFETSDealQuoteRep;

#define BrokerRepMng		GetBrokerReportManager()				//m_vctrep;	//Broker公司报价
#define BankClientRepMng	GetBankClientReportManager()			//m_vctbkclt;	//QB BankClient报价
#define BankRepMng			GetBankReportManager()					//Bank 报价
#define XCQuoteRepMng		GetXCQuoteReportManager()				//国债券期货：交易所报价
#define CfetsRepMng			GetCfetsReportManager()					//cfets报价
#define CfetsDealRepMng		GetCfetsDealQuoteManager()				//cfets成交行情

S_BONDLIB_EXPORT CSSReportManager<CBondCompanyRep> * GetBrokerReportManager();
S_BONDLIB_EXPORT CSSReportManager<CBondBankRep> *	GetBankClientReportManager();
S_BONDLIB_EXPORT CSSReportManager<CBondBankRep> *	GetBankReportManager();
S_BONDLIB_EXPORT CSSReportManager<CXCQuoteRep> *		GetXCQuoteReportManager();
S_BONDLIB_EXPORT CSSCFETSReportManager<CCFETSQuoteRep> *	GetCfetsReportManager();
S_BONDLIB_EXPORT CSSCFETSDealQuoteManager<CCFETSDealQuoteRep> *	GetCfetsDealQuoteManager();
